package com.credithc.signature.core.aop;

import com.credithc.signature.common.utils.DateUtil;
import com.credithc.signature.core.util.FixedLengthStack;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.StopWatch;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author zhanghanqiu181212@credithc.com
 * @Date 2020/12/21 10:09
 */
//@Component
//@Aspect
public class RunTimeAop implements ApplicationRunner {

    @Value("${spring.methods.runTime:handle,generatePDFToDisk,batchMakePersonalSeal,batchOfficialSign,batchPersonalSign,uploadPDF}")
    private String methods;

    @Value("${spring.methods.maxNum:10}")
    private Integer maxNum;



    private static HashMap<String, FixedLengthStack<String>> map = new HashMap<>();
    private static ArrayList<FixedLengthStack<String>> list = new ArrayList<>();


    /**
     * 初始化
     *
     * @param args
     * @throws Exception
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        if (StringUtils.isNotBlank(methods)) {
            String[] split = methods.split(",");
            for (int i = 0; i < split.length; i++) {
                FixedLengthStack<String> fixedLengthStack = new FixedLengthStack<>(maxNum, split[i]);
                list.add(fixedLengthStack);
                map.put(split[i], fixedLengthStack);
            }
        }
    }

    /**
     * 监控common中方法
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("execution( * com.credithc.signature.common.service.sign..*.*(..))")
    public Object doAround1(ProceedingJoinPoint pjp) throws Throwable {
        String methodName = getMethodName(pjp);
        FixedLengthStack<String> fixedLengthStack = map.get(methodName);
        Object proceed;
        if (fixedLengthStack != null) {
            // 创建一个计时器
            StopWatch watch = new StopWatch();
            // 计时器开始
            watch.start();
            // 执行方法
            proceed = pjp.proceed();
            // 计时器停止
            watch.stop();
            long time = watch.getTime();
           // updateExecuteTime(methodName, time);
        } else {
            proceed = pjp.proceed();
        }
        return proceed;
    }

    /**
     * 监控core中方法
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("execution( * com.credithc.signature.core.service..*.*(..))")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        String methodName = getMethodName(pjp);
        FixedLengthStack<String> fixedLengthStack = map.get(methodName);
        Object proceed;
        if (fixedLengthStack != null) {
            // 创建一个计时器
            StopWatch watch = new StopWatch();
            // 计时器开始
            watch.start();
            // 执行方法
            proceed = pjp.proceed();
            // 计时器停止
            watch.stop();
            long time = watch.getTime();
           // updateExecuteTime(methodName, time);
        } else {
            proceed = pjp.proceed();
        }
        return proceed;
    }

    /**
     * 获取方法名称
     *
     * @param pjp
     * @return
     * @throws NoSuchMethodException
     */
    public String getMethodName(ProceedingJoinPoint pjp) throws NoSuchMethodException {
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = pjp.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        return currentMethod.getName();
    }

//    /**
//     * 更新执行时间
//     *
//     * @param methodName
//     * @param time
//     */
//    private void updateExecuteTime(String methodName, long time) {
//        String dateStr = DateUtil.getStandardDateStr();
//        //每分钟
//        BoundZSetOperations<String, String> zSetOpsOneMintue = redisTemplate.boundZSetOps(dateStr + "#method#oneminute");
//        zSetOpsOneMintue.incrementScore(methodName, time);
//        if ("handle".equals(methodName)) {
//            zSetOpsOneMintue.incrementScore("executeCount", 1);
//        }
//        //每15分钟
//        BoundZSetOperations<String, String> zSetOpsFifteenMinute = redisTemplate.boundZSetOps(dateStr + "#method#fifteenminute");
//        zSetOpsFifteenMinute.incrementScore(methodName, time);
//        if ("handle".equals(methodName)) {
//            zSetOpsFifteenMinute.incrementScore("executeCount", 1);
//        }
//        //每小时
//        BoundZSetOperations<String, String> zSetOpsOneHour = redisTemplate.boundZSetOps(dateStr + "#method#onehour");
//        zSetOpsOneHour.incrementScore(methodName, time);
//        if ("handle".equals(methodName)) {
//            zSetOpsOneHour.incrementScore("executeCount", 1);
//        }
//        //每天
//        BoundZSetOperations<String, String> zSetOpsOneDay = redisTemplate.boundZSetOps(dateStr + "#method#oneday");
//        zSetOpsOneDay.incrementScore(methodName, time);
//        if ("handle".equals(methodName)) {
//            zSetOpsOneDay.incrementScore("executeCount", 1);
//        }
//    }

}
